package jms;
import java.sql.Connection;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.Properties;
import java.util.StringTokenizer;

import javax.jms.*;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;

import util.DB;
import util.Password;
import dao.Account;
import dao.AccountDAO;
import dao.AccountException;
import dao.Orderdetails;
import dao.OrderdetailsDAO;
import dao.Product;
import dao.ProductDAO;
import dao.ProductException;
import dao.Shoppingcart;
import dao.ShoppingcartDAO;
import dao.ShoppingcartException;

public class MarketPlaceServer implements MessageListener {

	private javax.jms.Connection connection;
	private Session session;
	private Topic marketTopic;
	private Queue marketQueue;
	private MessageConsumer consumer;
	private MessageConsumer consumerQ;

	private AccountDAO accDAO = new AccountDAO();
	private ProductDAO prodDAO = new ProductDAO();
	private ShoppingcartDAO cartDAO = new ShoppingcartDAO();
	private OrderdetailsDAO orderDAO = new OrderdetailsDAO();

	public java.sql.Connection con = DB.getConn();

	public void sendReply(Message request, String message) {
		try {
			MessageProducer MP = session.createProducer(null);
			Destination reply = request.getJMSReplyTo();
			TextMessage TM = session.createTextMessage();

			TM.setText("" + message); // Change
			MP.send(reply, TM); // Change

		} catch (JMSException JMSE) {
			System.out.println("JMS Exception: " + JMSE);
		}
	}

	public MarketPlaceServer() {
		try {
			Properties properties = new Properties();
			properties.put(Context.INITIAL_CONTEXT_FACTORY,
					"org.jnp.interfaces." + "NamingContextFactory");
			properties.put(Context.URL_PKG_PREFIXES, "org.jnp.interfaces");
			properties.put(Context.PROVIDER_URL, "localhost");

			InitialContext jndi = new InitialContext(properties);
			ConnectionFactory conFactory = (ConnectionFactory) jndi
					.lookup("XAConnectionFactory");
			connection = conFactory.createConnection();

			session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);

			try {
				marketTopic = (Topic) jndi.lookup("MarketTopic");
				marketQueue = (Queue) jndi.lookup("queue/MarketQueue");
			} catch (NamingException NE1) {
				System.out.println("NamingException: " + NE1
						+ " : Continuing anyway...");
			}

			if (null == marketTopic) {
				marketTopic = session.createTopic("MarketTopic");
				jndi.bind("MarketTopic", marketTopic);
			}
			if (null == marketQueue) {
				marketQueue = session.createQueue("queue/MarketQueue");
				jndi.bind("MarketQueue", marketQueue);
			}
			consumer = session.createConsumer(marketTopic);
			consumer.setMessageListener(this);
			consumerQ = session.createConsumer(marketQueue);
			consumerQ.setMessageListener(this);
			System.out.println("Server started waiting for client requests");
			connection.start();
		} catch (NamingException NE) {
			System.out.println("Naming Exception: " + NE);
		} catch (JMSException JMSE) {
			System.out.println("JMS Exception: " + JMSE);
			JMSE.printStackTrace();
		}
	}

	@Override
	public void onMessage(Message message) {

		try
		{
			TextMessage TM = (TextMessage)message;
			StringTokenizer strToken = new StringTokenizer(TM.getText(), "$");
			
			String operation = strToken.nextToken();
			String result = new String();
			String resultArr[];
			
			String emailId; 
			String fName;
			String lName;
			String password;
			if( operation.equals("signUp"))
			{
				emailId = strToken.nextToken();
				fName = strToken.nextToken();
				lName = strToken.nextToken();
				password = strToken.nextToken();
				result = String.valueOf(signUp(emailId, fName, lName, password));
				sendReply(message, result);
			}
			else if( operation.equals("signIn"))
			{
				emailId = strToken.nextToken();
				password = strToken.nextToken();
				signIn(emailId, password);
				result = String.valueOf(signIn(emailId, password));
				sendReply(message, result);
			}
			else if (operation.equals("fetchUserFName"))
			{
				result = fetchUserFName(strToken.nextToken());
				sendReply(message, result);
			}
			else if (operation.equals("fetchUserFName"))
			{
				result = fetchUserFName(strToken.nextToken());
				sendReply(message, result);
			}			
			
		}
		catch(JMSException JMSE)
		{
			System.out.println("JMS Exception: "+JMSE);
		}
	}

	public int signUp(String emailId, String fName, String lName,
			String password) {
		int result = 0;
		String passwordEncrypt = new String();

		passwordEncrypt = Password.encrypt(password, "MD5", "UTF8");
		try {
			if ((accDAO.findByEmailid(emailId, con)).length != 0) {
				result = 2;
			} else {
				Account account = new Account(emailId, fName, lName,
						passwordEncrypt, new Timestamp(new Date().getTime()));
				accDAO.insert(account, con);
			}
		} catch (Exception e) {
			result = 1;
		}
		return result;
	}

	public int signIn(String emailId, String password) {
		int result = 0;
		Object object[] = new Object[2];
		String passwordEncrypt = new String();

		passwordEncrypt = Password.encrypt(password, "MD5", "UTF8");
		object[0] = emailId;
		object[1] = passwordEncrypt;

		try {
			if (accDAO.findExecutingUserWhere("emailId=? and password=?",
					object, con).length == 0) {
				result = 2;
			}
		} catch (Exception e) {
			result = 1;
			System.out.println(e);
		}

		return result;
	}

	public String fetchUserFName(String emailId) {
		String result = "";
		try {
			result = accDAO.findByPrimaryKey(emailId, con).getFname();
		} catch (Exception e) {
			return "User";
		}
		return result;
	}

	public String fetchUserLastLoginTime(String emailId) {
		Timestamp tm;
		String result = "";
		try {
			tm = accDAO.findByPrimaryKey(emailId, con).getLastlogintime();
			result = tm.toString();
		} catch (Exception e) {
			return "01-01-2011 00:00:00";
		}
		return result;
	}

	public String[] fetchAdforHomePage(String emailId) {
		ArrayList<String> list = new ArrayList<String>();
		Account account[];
		String[] result;
		try {
			account = accDAO.findAll(con);
			result = new String[account.length - 1];
			for (int index = 0; index < account.length; index++) {
				if (account[index].getEmailid().equalsIgnoreCase(emailId)) {
					continue;
				} else {
					fetchAdFromEmailId(account[index].getEmailid(), list);
				}
			}
		} catch (Exception e) {
			result = new String[1];
			result[0] = new String(
					"ERR: Exception occured in the system. Please "
							+ "try again later.");
			return result;
		}

		result = Arrays.copyOf(list.toArray(), list.size(), String[].class);
		return result;
	}

	private void fetchAdFromEmailId(String emailId, ArrayList<String> list)
			throws AccountException, ProductException {
		String owner = "";
		String itemDetails = "";
		int quantity = 0;
		int price = 0;
		int productId = 0;

		Product prod[] = prodDAO.findByEmailid(emailId, con);
		Account acc = accDAO.findByPrimaryKey(emailId, con);
		owner = acc.getFname() + " " + acc.getLname();
		emailId = acc.getEmailid();

		for (int index = 0; index < prod.length; index++) {
			itemDetails = prod[index].getItemdetails();
			quantity = prod[index].getQuantity();
			price = prod[index].getPrice();
			productId = prod[index].getProductid();
			list.add(productId + ";" + owner + ";" + emailId + ";"
					+ itemDetails + ";" + quantity + ";" + price);
		}
	}

	private String[] fetchProdForCart(String emailId, ArrayList<String> list)
			throws AccountException, ProductException, ShoppingcartException {
		String owner = "";
		String ownerEmailId = "";
		String itemDetails = "";
		String result[];
		int quantity = 0;
		int price = 0;

		Product prod = new Product();
		Shoppingcart cart[] = cartDAO.findByEmailid(emailId, con);
		for (int index = 0; index < cart.length; index++) {
			prod = prodDAO.findByPrimaryKey(cart[index].getProductid(), con);
			ownerEmailId = prod.getEmailid();
			Account acc = accDAO.findByPrimaryKey(ownerEmailId, con);
			owner = acc.getFname() + " " + acc.getLname();
			itemDetails = prod.getItemdetails();
			quantity = cart[index].getQuantity();
			price = prod.getPrice();
			list.add(owner + ";" + ownerEmailId + ";" + itemDetails + ";"
					+ quantity + ";" + price);
		}
		result = Arrays.copyOf(list.toArray(), list.size(), String[].class);

		return result;
	}

	public String addToCart(String emailId, String productIdStr, int quantity) {
		String result = "";
		try {
			int productId = Integer.parseInt(productIdStr);
			Shoppingcart cart = new Shoppingcart();
			Product prod = prodDAO.findByPrimaryKey(productId, con);

			if (prod.getQuantity() < quantity) {
				result = "ERR: Cannot be added to cart as the quantity is not "
						+ "available as requested. Go to home page and try again";
			} else {
				cart.setEmailid(emailId);
				cart.setProductid(productId);
				cart.setCreateddate(new java.sql.Date(System
						.currentTimeMillis()));
				cart.setQuantity(quantity);
				cartDAO.insert(cart, con);
			}
		} catch (Exception e) {
			result = "ERR: Exception " + e + " occured in the system. "
					+ "Please try again.";
		}
		return result;
	}

	public String removeFromCart(String emailId, String productIdStr) {
		String result = "";
		Object object[] = new Object[2];

		object[0] = productIdStr;
		object[1] = emailId;

		try {
			Shoppingcart[] cart = cartDAO.findExecutingUserWhere(
					"productId=? and " + "emailId=?", object, con);
			if (cart.length == 0) {
				result = "ERR: Cannot be removed to cart as the item is not "
						+ "available in cart. Go to home page and try again.";
			} else {
				cartDAO.delete(cart[0].getIdshoppingcart(), con);
			}
		} catch (Exception e) {
			result = "ERR: Exception " + e + " occured in the system. "
					+ "Please try again.";
		}
		return result;
	}

	public String[] viewCart(String emailId) {
		ArrayList<String> list = new ArrayList<String>();
		String[] result;
		try {
			result = fetchProdForCart(emailId, list);
		} catch (Exception e) {
			result = new String[1];
			result[0] = new String(
					"ERR: Exception occured in the system. Please "
							+ "try again later.");
		}
		return result;
	}

	public String checkOut(String emailId) {
		String result = "";
		try {
			Shoppingcart cart[];
			// Find all the carts.
			cart = cartDAO.findByEmailid(emailId, con);
			if (cart.length == 0) {
				result = "ERR: No Items to check out in the CART. Please add items "
						+ "to the cart visiting the home page.";
			} else {
				for (int index = 0; index < cart.length; index++) {
					Product prod = prodDAO.findByPrimaryKey(
							cart[index].getProductid(), con);
					if (cart[index].getQuantity() > prod.getQuantity()) {
						result = "ERR: Cannot checkout Item with details : "
								+ "Product Name - " + prod.getItemdetails()
								+ " Quantity Available: " + prod.getQuantity()
								+ " Quantity to buy : "
								+ cart[index].getQuantity()
								+ ".Please remove the item from cart and then "
								+ "check out.";

						break;
					}
				}
			}
		} catch (Exception e) {
			result = "ERR: Exception occured in the system. Please try again "
					+ "logging.";
		}
		return result;
	}

	public String payment(String emailId, String creditNum, String cvvNo) {
		String result = "";

		if (creditNum.length() < 16) {
			result = "ERR: Enter a valid credit card number. The credit card "
					+ "number should be of 16 digits. Try check out of the "
					+ "products again.";
			return result;
		}
		try {
			// Populate the order details table.
			Orderdetails order = new Orderdetails();
			Shoppingcart cart[] = cartDAO.findByEmailid(emailId, con);
			order.setEmailid(emailId);
			for (int index = 0; index < cart.length; index++) {
				Product prod = prodDAO.findByPrimaryKey(
						cart[index].getProductid(), con);
				order.setOrderdate(new java.sql.Date(System.currentTimeMillis()));
				order.setProductid(cart[index].getProductid());
				order.setQuantity(cart[index].getQuantity());
				order.setTotalprice(cart[index].getQuantity() * prod.getPrice());
				prod.setQuantity(prod.getQuantity() - cart[index].getQuantity());

				orderDAO.insert(order, con);
				prodDAO.update(prod.getProductid(), prod, con);
				cartDAO.delete(cart[index].getIdshoppingcart(), con);
			}

		} catch (Exception e) {
			result = "ERR: Exception " + e
					+ " occured in the system. Please try " + "again later.";
		}
		return result;
	}

	public String hostANewProduct(String emailId, String quantity,
			String price, String itemDetails) {
		String result = "";

		try {
			Product product = new Product();
			int quantityInt = Integer.parseInt(quantity);
			int priceInt = Integer.parseInt(price);

			product.setEmailid(emailId);
			product.setItemdetails(itemDetails);
			product.setPrice(priceInt);
			product.setQuantity(quantityInt);

			prodDAO.insert(product, con);
		} catch (Exception e) {
			result = "ERR: Exception " + e
					+ " occured in the system. Please try " + "again later.";
		}
		return result;
	}

	public String[] getOrderSummary(String emailId) {
		String result[];
		ArrayList<String> list = new ArrayList<String>();
		try {
			Orderdetails order[];
			order = orderDAO.findByEmailid(emailId, con);

			for (int index = 0; index < order.length; index++) {
				fetchOrderDetails(list, order[index]);
			}
		} catch (Exception e) {
			result = new String[1];
			result[0] = "ERR: Exception " + e
					+ " occured in the system . Please try " + "again later.";
		}
		result = Arrays.copyOf(list.toArray(), list.size(), String[].class);
		return result;
	}

	private void fetchOrderDetails(ArrayList<String> list, Orderdetails order)
			throws ProductException {
		String emailId = order.getEmailid();
		java.sql.Date date = order.getOrderdate();
		int prodId = order.getProductid();
		int quantity = order.getQuantity();
		int totalPrice = order.getTotalprice();
		Product prod = prodDAO.findByPrimaryKey(prodId, con);

		list.add(emailId + ";" + date.toString() + ";" + prod.getItemdetails()
				+ ";" + quantity + ";" + totalPrice);
	}
	public static void main(String a[])
	{
		new MarketPlaceServer();
	}
}
